Release 10.1A: OpenEdge Development:
Messaging and ESB


Enhanced XML support

Prior to OpenEdge Release 10.1, the OpenEdge Adapter for SonicMQ supported using the XMLMessage type if the client created the message as text in a well-formed XML document.

In OpenEdge Release 10.1, clients can send additional types of data, such as temp-tables and ProDatasets, as XMLMessage. The TempTableMessage and DataSetMessage transport data to the SonicMQ Broker using XML. The 4GL has built-in functionality to transform TEMP-TABLE or ProDataSet data into XML. Additionally, 4GL clients read, write, and parse XML using SAX-READER, SAX-WRITER, and X-DOCUMENT.

For more information on accessing the examples files, see the "Example procedures" section.

The following example shows how to use the SAX-WRITER object:

Saxwriter message example
DEFINE VARIABLE sessionH AS HANDLE no-undo. 
DEFINE VARIABLE mesgH AS HANDLE no-undo. 
RUN jms/jmssession.p PERSISTENT SET sessionH ("-SMQConnect"). 
RUN SETBrokerURL IN sessionH ("-H localhost -S 5162 "). 
RUN beginSession IN sessionH. 
DEFINE VARIABLE saxWriterH AS HANDLE NO-UNDO. 
RUN createXMLMessage IN sessionH (OUTPUT mesgH). 
saxWriterH = DYNAMIC-FUNCTION('getSaxWriter':u IN mesgH, ?). 
/* Will write an envelope address */ 
saxWriterH:FORMATTED = TRUE. 
/* Want to format this so it is easy to read */ 
saxWriterH:START-DOCUMENT(). 
/* The ENCODING           attribute defaults to UTF-8 */ 
/* The FRAGMENT           attribute defaults to FALSE */ 
/* The STRICT             attribute defaults to TRUE  */ 
saxWriterH:START-ELEMENT("mailingaddress"). 
RUN xmlData(INPUT "name", INPUT "Joe Perry"). 
saxWriterH:START-ELEMENT("address").  
/* This node contains an attribute */ 
saxWriterH:INSERT-ATTRIBUTE("type", "personal"). 
RUN xmlData(INPUT "street",  INPUT "11 Sugerland St."). 
RUN xmlData(INPUT "city",    INPUT "Somerville"). 
RUN xmlData(INPUT "state",   INPUT "MA"). 
RUN xmlData(INPUT "zipcode", INPUT "02143"). 
saxWriterH:END-ELEMENT("address"). 
saxWriterH:START-ELEMENT("address").  
saxWriterH:INSERT-ATTRIBUTE("type", "business"). 
RUN xmlData(INPUT "name",   INPUT "Progress Software"). 
RUN xmlData(INPUT "street", INPUT "14 Oak Park"). 
RUN xmlData(INPUT "city",   INPUT "Bedford"). 
RUN xmlData(INPUT "state",  INPUT "MA"). 
RUN xmlData(INPUT "zip",    INPUT "01730"). 
saxWriterH:END-ELEMENT("address"). 
saxWriterH:WRITE-EMPTY-ELEMENT("default").  
saxWriterH:INSERT-ATTRIBUTE("type", "personal"). 
saxWriterH:END-ELEMENT("mailingaddress"). 
saxWriterH:END-DOCUMENT(). 
RUN deleteSaxWriter IN mesgH (saxWriterH). 
RUN sendToQueue IN sessionH ("SampleQ1", mesgH, ?, ?, ?). 
RUN deleteMessage IN mesgH. 
PROCEDURE xmlData: 
DEFINE INPUT PARAMETER xmlNode AS CHARACTER. 
DEFINE INPUT PARAMETER charData AS CHARACTER. 
    saxWriterH:START-ELEMENT(xmlNode). 
    saxWriterH:WRITE-CHARACTERS(charData). 
    saxWriterH:END-ELEMENT(xmlNode). 
END PROCEDURE. 

The following example shows how to use the setSaxReader procedure:

setSaxReader example  
DEFINE VARIABLE saxH AS HANDLE NO-UNDO. 
CREATE SAX-READER saxH. 
/* SAX-READER setup as needed */ 
PROCEDURE messageHandler: 
DEFINE INPUT PARAMETER messageH AS HANDLE NO-UNDO. 
DEFINE INPUT PARAMETER messageConsumerH AS HANDLE NO-UNDO. 
DEFINE OUTPUT PARAMETER autoReplyH AS HANDLE NO-UNDO. 
DEFINE VARIABLE resultH AS HANDLE NO-UNDO. 
DEFINE VARIABLE mtype AS CHAR NO-UNDO. 
mtype =  DYNAMIC-FUNCTION('getMessageType':u IN messageH). 
IF mtype = "TemptableMessage" THEN DO: 
    resultH = DYNAMIC-FUNCTION('GetTempTable':u IN messageH, ?, ?, ? ). 
    /* TempTable actions as needed */ 
END. 
IF mtype = "DatasetMessage" THEN DO: 
    resultH = DYNAMIC-FUNCTION('GetDataSet':u IN messageH, ?, ?, ? ). 
    /* DataSet actions as needed */ 
END. 
IF mtype = "XMLMessage" THEN DO: 
    RUN setSaxReader IN messageH (saxH). 
    saxH:SAX-PARSE(). 
END. 
RUN deleteMessage IN messageH. 
END. 

The SAX-WRITER object reads XML from a file using the SAX-READER object and send it to a queue using an XMLMessage. The following example shows how to use the SAX-WRITER object:

saxSender.p
DEFINE VARIABLE sessionH AS HANDLE NO-UNDO. 
DEFINE VARIABLE mesgH AS HANDLE NO-UNDO. 
DEFINE VARIABLE hdl1 AS HANDLE NO-UNDO. 
DEFINE VARIABLE hdl2 AS HANDLE NO-UNDO. 
/* Start up the session to the SonicMQ broker */ 
RUN jms/ptpsession.p PERSISTENT SET sessionH ("-H localhost -S 5162 "). 
RUN setBrokerURL IN sessionH ("localhost:2506"). 
RUN beginSession IN sessionH. 
/* Create the Sonic XML message */ 
RUN createXMLMessage IN sessionH (OUTPUT mesgH). 
/* 
   The Adapter function GetSaxWriter will return a handle to a 
   newly created SAX-WRITER and set its output to a destination local 
   to the Adapter.  The application may then make normal SAX-WRITER 
   calls using this handle. 
*/ 
hdl2 = DYNAMIC-FUNCTION('GetSaxWriter':u IN mesgH, ?). 
hdl2:START-DOCUMENT(). 
/* 
   Create a SAX-READER to read in the xml file to be sent in a 
   SonicMQ XML message.  The SAX-READER callback procedures will 
   use the handle to the SAX-WRITER just created to copy the XML. 
*/ 
CREATE SAX-READER hdl1. 
hdl1:SET-INPUT-SOURCE("FILE", "personal.xml"). 
hdl1:SAX-PARSE(). 
DELETE OBJECT hdl1. 
hdl2:END-DOCUMENT(). 
/* 
   The Adapter procedure DeleteSaxWriter will copy the XML written with 
   the SAX-WRITER calls into the SonicMQ XML message.  It will then delete 
   the SAX-WRITER specified by the handle. 
*/ 
RUN DeleteSaxWriter IN mesgH (hdl2). 
/* Send the XML message. */ 
RUN sendToQueue IN sessionH ("SampleQ1", mesgH, ?, ?, ?). 
/* Disconnect the session from the SonicMQ broker */ 
RUN deleteMessage IN mesgH. 
RUN deleteSession IN sessionH. 
/*****************************************************/ 
/* callbacks for the SAX-READER function SAX-PARSE() */ 
/*****************************************************/ 
/* This procedure is called when the parser finds the start tag for an element. 
*/ 
PROCEDURE StartElement: 
DEFINE INPUT PARAMETER namespaceURI AS CHARACTER. 
DEFINE INPUT PARAMETER localName AS CHARACTER. 
DEFINE INPUT PARAMETER qname AS CHARACTER. 
DEFINE INPUT PARAMETER attributes AS HANDLE. 
hdl2:START-ELEMENT(localName, namespaceURI). 
END. 
/* This callback gets passed the character data for an element. */ 
PROCEDURE Characters: 
DEFINE INPUT PARAMETER charData AS MEMPTR. 
DEFINE INPUT PARAMETER numChars AS INTEGER. 
DEFINE VARIABLE data AS CHARACTER NO-UNDO. 
data = GET-STRING(charData, 1, GET-SIZE(charData)). 
hdl2:WRITE-CHARACTERS(data). 
END. 
/* This callback is called when the parser finds the end tag for an Element. */ 
PROCEDURE EndElement: 
DEFINE INPUT PARAMETER namespaceURI AS CHARACTER. 
DEFINE INPUT PARAMETER localName AS CHARACTER. 
DEFINE INPUT PARAMETER qName AS CHARACTER. 
hdl2:END-ELEMENT(localName, namespaceURI). 
END. 

TheSAX-READER object reads an XMLMessage from a queue and writes it to a LONGCHAR. The following example shows how to use the SAX-READER object:

saxReceiver.p
DEFINE VARIABLE sessionH AS HANDLE NO-UNDO. 
DEFINE VARIABLE msgConsumer AS HANDLE NO-UNDO. 
DEFINE VARIABLE mesgH AS HANDLE NO-UNDO. 
DEFINE VARIABLE hdl2 AS HANDLE NO-UNDO. 
DEFINE VARIABLE stillWaiting AS LOGICAL INIT yes. 
DEFINE VARIABLE lch AS LONGCHAR NO-UNDO view-as editor size 70 by 30 large. 
/* Start up the session to the SonicMQ broker */ 
RUN jms/ptpsession.p PERSISTENT SET sessionH ("-H localhost -S 5162 "). 
RUN setBrokerURL IN sessionH ("localhost:2506"). 
RUN beginSession IN sessionH. 
/* Create the message consumer and start receiving messages. */ 
RUN createMessageConsumer IN sessionH (THIS-PROCEDURE, 
                                       "messageHandler", 
                                       OUTPUT msgConsumer). 
RUN receiveFromQueue IN sessionH ("SampleQ1", ?, msgConsumer). 
RUN startReceiveMessages IN sessionH. 
/* Wait for all messages to be received. */ 
RUN waitForMessages IN sessionH ("inWait", THIS-PROCEDURE, ?). 
RUN deleteSession IN sessionH. 
/* Message handler procedure */ 
PROCEDURE messageHandler: 
DEFINE INPUT PARAMETER messageH AS HANDLE NO-UNDO. 
DEFINE INPUT PARAMETER messageConsumerH AS HANDLE NO-UNDO. 
DEFINE OUTPUT PARAMETER autoReplyH AS HANDLE NO-UNDO. 
DEFINE VARIABLE hdl1 AS HANDLE NO-UNDO. 
CREATE SAX-WRITER hdl2. 
hdl2:SET-OUTPUT-DESTINATION("LONGCHAR",lch). 
hdl2:START-DOCUMENT(). 
CREATE SAX-READER hdl1. 
/* 
  The Adapter procedure SetSaxReader will set the input source 
  for a SAX-READER to the XML message that has been received. 
  The application may then use normal SAX-READER calls to access 
  the XML from the message. 
*/ 
RUN SetSaxReader IN messageH (hdl1). 
hdl1:SAX-PARSE(). 
DELETE OBJECT hdl1. 
RUN deleteMessage IN messageH. 
hdl2:END-DOCUMENT(). 
DISPLAY lch. 
lch = "". 
stillWaiting = FALSE. 
END. 
FUNCTION inWait RETURNS LOGICAL. 
RETURN stillWaiting. 
END. 
/*****************************************************/ 
/* callbacks for the SAX-READER function SAX-PARSE() */ 
/*****************************************************/ 
/* 
   This procedure is called when the parser finds the start tag for an element. 
*/ 
PROCEDURE StartElement: 
DEFINE INPUT PARAMETER namespaceURI AS CHARACTER. 
DEFINE INPUT PARAMETER localName AS CHARACTER. 
DEFINE INPUT PARAMETER qname AS CHARACTER. 
DEFINE INPUT PARAMETER attributes AS HANDLE. 
hdl2:START-ELEMENT(localName, namespaceURI). 
END. 
/* This callback gets passed the character data for an element.*/ 
PROCEDURE Characters: 
DEFINE INPUT PARAMETER charData AS MEMPTR. 
DEFINE INPUT PARAMETER numChars AS INTEGER. 
DEFINE VARIABLE data AS CHARACTER NO-UNDO. 
data = GET-STRING(charData, 1, GET-SIZE(charData)). 
hdl2:WRITE-CHARACTERS(data). 
END. 
/* This callback is called when the parser finds the end tag for an Element.*/ 
PROCEDURE EndElement: 
DEFINE INPUT PARAMETER namespaceURI AS CHARACTER. 
DEFINE INPUT PARAMETER localName AS CHARACTER. 
DEFINE INPUT PARAMETER qName AS CHARACTER. 
hdl2:END-ELEMENT(localName, namespaceURI). 
END. 

The following example shows how to use the setX-Document procedure:

setX-Document example  
CREATE x-document hdl1. 
hdl1:LOAD("file", "4k.xml", false). 
RUN createXMLMessage IN sessionH (OUTPUT mesgH). 
RUN setX-Document IN mesgH(hdl1). 
RUN sendToQueue IN sessionH ("SampleQ1", mesgH, ?, ?, ?). 
RUN deleteMessage IN mesgH. 

The following example shows how to use getX-Document function:

getX-Document example  
PROCEDURE messageHandler: 
DEFINE INPUT PARAMETER messageH AS HANDLE NO-UNDO. 
DEFINE INPUT PARAMETER messageConsumerH AS HANDLE NO-UNDO. 
DEFINE OUTPUT PARAMETER autoReplyH AS HANDLE NO-UNDO. 
DEFINE VARIABLE resultH AS HANDLE NO-UNDO. 
DEFINE VARIABLE mtype AS CHAR NO-UNDO. 
mtype = DYNAMIC-FUNCTION('getMessageType':u IN messageH). 
IF mtype = "TemptableMessage" THEN DO: 
    resultH = DYNAMIC-FUNCTION('GetTempTable':u IN messageH, ?, ?, ? ). 
    /* TempTable actions as needed */ 
END. 
IF mtype = "DatasetMessage" THEN DO: 
    resultH = DYNAMIC-FUNCTION('GetDataSet':u IN messageH, ?, ?, ? ). 
    /* DataSet actions as needed */ 
END. 
IF mtype = "XMLMessage" THEN DO: 
    resultH = DYNAMIC-FUNCTION('getX-Document':u IN messageH). 
    /* x-document calls as needed */ 
END. 
RUN deleteMessage IN messageH. 
END. 

The X-DOCUMENT object reads XML from a file and sends it to a queue using an XMLMessage. The following example shows how to use X-DOCUMENT object to send a message:

domSender.p  
DEFINE VARIABLE sessionH AS HANDLE NO-UNDO. 
DEFINE VARIABLE mesgH AS HANDLE NO-UNDO. 
DEFINE VARIABLE hdl1 AS HANDLE NO-UNDO. 
/* Start up the session to the SonicMQ broker */ 
RUN jms/ptpsession.p PERSISTENT SET sessionH ("-H localhost -S 5162 "). 
RUN setBrokerURL IN sessionH ("localhost:2506"). 
RUN beginSession IN sessionH. 
/* Create the Sonic XML message */ 
RUN createXMLMessage IN sessionH (OUTPUT mesgH). 
/* Load the XML file. */ 
CREATE X-DOCUMENT hdl1. 
hdl1:LOAD("file", "personal.xml", false). 
/* 
   The Adapter function SetX-Document will copy the XML 
   from the X-DOCUMENT into the XML message. 
*/ 
RUN setX-Document IN mesgH(hdl1). 
DELETE OBJECT hdl1. 
/* Send the XML message. */ 
RUN sendToQueue IN sessionH ("SampleQ1", mesgH, ?, ?, ?). 
/* Disconnect the session from the SonicMQ broker */ 
RUN deleteMessage IN mesgH. 
RUN deleteSession IN sessionH. 

The X-DOCUMENT object reads an XMLMessage from a queue and writes it to a LONGCHAR. The following example shows how to use X-DOCUMENT object to receive a message:

domReceiver.p
DEFINE VARIABLE sessionH AS HANDLE NO-UNDO. 
DEFINE VARIABLE msgConsumer AS HANDLE NO-UNDO. 
DEFINE VARIABLE stillWaiting AS LOGICAL INIT yes. 
DEFINE VARIABLE lch AS LONGCHAR NO-UNDO view-as editor size 70 by 30 large. 
/* Start up the session to the SonicMQ broker */ 
RUN jms/ptpsession.p PERSISTENT SET sessionH ("-H localhost -S 5162 "). 
RUN setBrokerURL IN sessionH ("localhost:2506"). 
RUN beginSession IN sessionH. 
/* Create the message consumer and start receiving messages. */ 
RUN createMessageConsumer  
    IN sessionH ( THIS-PROCEDURE, "messageHandler", OUTPUT msgConsumer). 
RUN receiveFromQueue IN sessionH ("SampleQ1", ?, msgConsumer). 
RUN startReceiveMessages IN sessionH. 
/* Wait for all messages to be received. */ 
RUN waitForMessages IN sessionH ("inWait", THIS-PROCEDURE, ?). 
RUN deleteSession IN sessionH. 
/* Message handler procedure */ 
PROCEDURE messageHandler: 
DEFINE INPUT PARAMETER messageH AS HANDLE NO-UNDO. 
DEFINE INPUT PARAMETER messageConsumerH AS HANDLE NO-UNDO. 
DEFINE OUTPUT PARAMETER autoReplyH AS HANDLE NO-UNDO. 
DEFINE VARIABLE hdl1 AS HANDLE NO-UNDO. 
/* 
  The Adapter function GetX-Document will return a handle to a newly 
  created X-DOCUMENT and load it with the XML message that has been received. 
  The application may then use normal X-DOCUMENT calls to access 
  the XML from the message. 
*/ 
hdl1 = DYNAMIC-FUNCTION('GetX-Document':u IN messageH). 
hdl1:SAVE("LONGCHAR",lch). 
DELETE OBJECT hdl1. 
RUN deleteMessage IN messageH. 
DISPLAY lch. 
lch = "". 
stillWaiting = FALSE. 
END. 
FUNCTION inWait RETURNS LOGICAL. 
RETURN stillWaiting. 
END. 


Copyright © 2005 Progress Software Corporation
www.progress.com
Voice: (781) 280-4000
Fax: (781) 280-4095